/*  -*- mode: c++; coding: utf-8; c-file-style: "stroustrup"; -*-

    Copyright 2008 Asier Aguirre <asier.aguirre@gmail.com>
    This file is part of Intromit.

    Intromit is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Intromit is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Intromit.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef SOURCE_HH
#define SOURCE_HH
//! \addtogroup intromit_core
//@{

// INCLUDES
#include <stdlib.h>

// DECLARATIONS
class string_index;

// CLASSES

//! Manages a single source file and references from metadata
class source_file
{
    struct comment
    {
	int i_com;                 // com_str[i_com]
	int i_attr, i_attr_block;  // attrs for near comment and block attrs [attr_index]
	int ini_line, end_line;    // starting in 0
    };

    // file data
    int i_name;
    char *data;
    int n_data;

    // lines
    int *line, n_line, max_line;      // line[0] points to 0 in data, that is, line 1

    // comments
    comment *com;
    int n_com, max_com;
    char *com_str;
    int n_com_str, max_com_str;

    // featured lines
    int *feat;                        // array of lines starting in 0
    int n_feat, max_feat;

    // ** PRIVATE FUNCTIONS **
    bool load(char *filename);

    void preparse();
    void preparse_add_comment(int &first_line, int &first_line_col, int col, char c);
    void preparse_remove_comment_last_spaces();
    void preparse_add_comment_char(char c);

    void postparse(char *prefix, char *separator, char *ini, char *fin, char *neg, char *offline,
		   string_index *attr_index);
    static char *postparse_normalize_attributes(char *&str, char *prefix, char *separator,
						char *ini, char *fin, char *neg,
						char *offline, string_index *attr_index,
						bool *have_ini, bool*have_fin);
    static void postparse_offline(char *off, char *separator, char *neg, string_index *attr_index);
    static void postparse_offline_block(char *off, char *separator, char *neg, string_index *attr_index, int i_namespace);
    static char *postparse_offline_attr(char *str, char *separator, char *neg);


    int search_comment(int end_line_from_0);
    int search_feature_line(int line);
    int search_line(int i_data);
    void locate_class_method(char *method_name, int n_method_name, string_index *&dev, int ini, int end);

    // internal
    void dtor();

public:
    source_file();
    ~source_file();

    bool init(int i_name, string_index *doc,
	      char *prefix, char *separator, char *ini, char *fin, char *neg, char *offline,
	      string_index *attr_index);

    //! @name Functionality
    //@{
    bool add_feature_line(int line_from_1);
    char *comment(int line_from_1);
    char *attributes(int line_from_1, string_index *attr_index, char *attr_separator, char *attr_neg);

    int match_regex(char *regex, int line_min_from_1, int line_max_from_1); // return line from 0
    string_index *locate_class_method(int i_name_class, int line, int i_method_name, string_index *doc); //@}

    //! Setters
    void set_i_name(int i_name);

    //! @name Getters
    //@{
    inline int get_i_name() {return i_name;}
    inline int get_n_lines() {return n_line;} //@}

    //! @name Debug
    //@{
    void dump_featured_lines();
    void dump_comments();
    void dump(string_index *attr_index=NULL); //@}

    static char *postparse_join_attributes(char *str1, char *str2, char *separator, char *neg);
};

//! Manages a group of source files
class source
{
    // the source files
    source_file **file;
    int n_file, max_file;

    // string index from dwarf
    string_index *doc;

    // attribute params
    char *attr_prefix, *attr_separator, *attr_ini, *attr_fin, *attr_neg, *attr_offline;
    string_index *attr_index;

    // ** PRIVATE FUNCTIONS **
    int search_file(int i_name);
    int search_or_add_file(int i_name);

public:
    source();
    ~source();

    // init class
    bool init(string_index *doc, char *prefix, char *separator, char *ini, char *fin, char *neg, char *offline);
    bool reindex(string_index *doc);

    //! Adds lines for different features
    bool add_feature_line(int i_filename, int line);

    //! Returns a volatile string with the comment corresponding to feature in that line
    char *comment(int i_filename, int line_from_1);

    //! Returns true if attr is in attr_list
    static bool has_attr(char *attr_list, char *attr);
    //! Returns true if ~attr is in attr_list
    static bool has_neg_attr(char *attr_list, char *attr_without_neg_prefix);

    //! Returns a volatile string with the attributes corresponding to feature in that line
    char *attributes(int i_filename, int line, char *namespc=NULL, char *name=NULL);

    //! Returns line of first command that matches regex in a source zone or -1 if no match
    int match_regex(int i_filename, char *regex, int line_min_from_1=0, int line_max_from_1=0);

    //! Returns the prototypes that match method_name in the class
    string_index *locate_class_method(int i_name_class, int i_filename, int line, int i_method_name);


    //! @name Debug
    //@{
    void dump_featured_lines(int i_filename=-1);
    void dump_comments(int i_filename=-1);
    void dump(int i_filename=-1);
    void dump_offline_attrs(const char *filename=NULL); //@}
};

//@}
#endif
